﻿/*
 * This file is the definition of the class AudioOutStreamSource. The class is to stream the audio byte buffer for 
 * the background audio player to play.
 * 
 * Author: Minh Luan
 * Date: 24/04/2012
 */

using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Media;
using LumiSoft.Net.Media;
using LumiSoft.Net.Media.Codec.Audio;
using System.Globalization;

namespace BackgroundMediaSource
{
    /// <summary>
    /// A Media Stream Source implemented to play PGM audio
    /// </summary>
    public class AudioOutStreamSource : MediaStreamSource
    {
        private MediaStreamDescription _audioDesc;
        private LumiSoft.Net.Media.AudioFormat _pcmAudioFormat;
        private Queue<byte[]> _receivedAudioBuffers;
        private WAVEFORMATEX _waveFormat;
        private const double convertToSeconds = 10000000.0;
        private Dictionary<MediaSampleAttributeKeys, string> _emptySampleDict = new Dictionary<MediaSampleAttributeKeys, string>();
        public event EventHandler StreamComplete;
        private readonly object m_locker = new object();    //To lock the queue

        /// <summary>
        /// Constructor
        /// </summary>
        public AudioOutStreamSource(Queue<byte[]> receivedAudioBuffers)
        {
            if (receivedAudioBuffers == null)
            {
                throw new ArgumentNullException("receivedAudioBuffers");
            }
            _receivedAudioBuffers = receivedAudioBuffers;

            // Initialize the PCM audio format
            _pcmAudioFormat = new LumiSoft.Net.Media.AudioFormat(16000, 16, 1);


        }

        /// <summary>
        /// Override method OpenMediaAsync
        /// </summary>
        protected override void OpenMediaAsync()
        {
            // Create a parser
            Dictionary<MediaStreamAttributeKeys, string> streamAttributes = new Dictionary<MediaStreamAttributeKeys, string>();
            Dictionary<MediaSourceAttributesKeys, string> sourceAttributes = new Dictionary<MediaSourceAttributesKeys, string>();
            List<MediaStreamDescription> availableStreams = new List<MediaStreamDescription>();

            // Stream Description
            _waveFormat = new WAVEFORMATEX();
            _waveFormat.BitsPerSample = (short)_pcmAudioFormat.BitsPerSample;
            _waveFormat.Channels = (short)_pcmAudioFormat.Channels;
            _waveFormat.FormatTag = 1;  // Format.PCM
            _waveFormat.SamplesPerSec = _pcmAudioFormat.SamplesPerSecond;
            _waveFormat.Size = 0;   //Must be 0
            _waveFormat.BlockAlign = (short)(_waveFormat.Channels * _waveFormat.BitsPerSample / 8);
            _waveFormat.AvgBytesPerSec = _waveFormat.SamplesPerSec * _waveFormat.Channels * _waveFormat.BitsPerSample / 8;

            streamAttributes[MediaStreamAttributeKeys.CodecPrivateData] = _waveFormat.ToHexString();
            MediaStreamDescription msd = new MediaStreamDescription(MediaStreamType.Audio, streamAttributes);

            _audioDesc = msd;
            availableStreams.Add(_audioDesc);

            //Endless stream
            sourceAttributes[MediaSourceAttributesKeys.Duration] = TimeSpan.FromMinutes(0).Ticks.ToString(CultureInfo.InvariantCulture);
            ReportOpenMediaCompleted(sourceAttributes, availableStreams);
        }


        protected void CallStreamComplete()
        {
            // This may throw a null reference exception - that indicates that the agent did not correctly
            // subscribe to StreamComplete so it could call NotifyComplete
            if (null != StreamComplete)
            {
                StreamComplete(this, new EventArgs());
            }
        }

        protected override void CloseMedia()
        {
            // Close the stream
            _audioDesc = null;
            CallStreamComplete();
        }

        protected override void GetDiagnosticAsync(MediaStreamSourceDiagnosticKind diagnosticKind)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Override method GetSampleAsync. 
        /// </summary>
        /// <param name="mediaStreamType">Enumeration that specifies the type of stream</param>
        protected override void GetSampleAsync(MediaStreamType mediaStreamType)
        {
            byte[] decodedBuffer;
            lock (m_locker)
            {
                if (_receivedAudioBuffers.Count > 0)
                {
                    decodedBuffer = _receivedAudioBuffers.Dequeue();
                }
                else
                {
                    // TODO: Xử lý trường hợp không nhận được decodedBuffer
                }
            }
        }
    }
}